﻿using System;
using Microsoft.Xna.Framework;
using ProtoGame.GameLib;
using ProtoGame.DescritoresContent;
using ProtoGame.Sprites;
using ProtoGame.Input;
using ProtoGame.RegioesGatilho;
using Microsoft.Xna.Framework.Audio;
using ProtoGame.GameLib.Entities;
using Microsoft.Xna.Framework.Graphics;

namespace ProtoGame.Fases.Labirinto
{
    class PGLabirintos<TIdSaidas> where TIdSaidas : struct
    {
        struct DialogosDesc
        {
            public Rectangle Regiao;
            public byte Id;

            public DialogosDesc(Rectangle regiao, byte id)
            {
                this.Regiao = regiao;
                this.Id = id;
            }
        }

        struct NPCDesc
        {
            public enum Direcoes
            {
                Cima,
                Baixo,
                Esquerda,
                Direita
            }

            public NPCDesc(Vector2 Posicao, Direcoes Direcao)
            {
                this.Posicao = Posicao;
                this.Direcao = Direcao;
            }

            public Vector2 Posicao;
            public Direcoes Direcao;
        }

        struct LabirintoDesc
        {
            public ushort[,] Solo;
            public Rectangle[] Impassaveis;
            public Rectangle[] EscadasProximo;
            public Rectangle? EscadaEntrada;
            public Vector2[] Inimigos;
            public NPCDesc[] NPCs;
            public DialogosDesc[] Dialogos;
            public Point JogadorInicio;
        }

        LabirintoDesc Inicio;
        LabirintoDesc OneWay;
        LabirintoDesc TwoWay;
        LabirintoDesc SemFim;
        LabirintoDesc Fim;

        Game game;
        IPGEntradasAcao entradas;
        Tileset labirintoGfx;
        Tileset koboldGfx;
        Tileset espadaGfx;
        Tileset ursoGfx;
        Texture2D placaGfx;
        SoundEffect espadaSfx;
        SoundEffect castursoSfx;
        SpriteFont placaFont;

        TIdSaidas[] listaProximos;
        TIdSaidas saidaVolta;
        uint alturaMaxima;

        public PGLabirintos(uint altura, TIdSaidas saidaVolta, TIdSaidas[] listaProximos, Game game)
        {
            #region Dados Inicio
            Inicio.Solo = new ushort[,] {
                {77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77},
                {77,77,47,107,107,107,107,107,107,107,107,107,46,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77},
                {77,77,78,196,197,198,134,134,134,134,134,134,76,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77},
                {77,77,78,226,227,228,134,134,134,134,134,134,76,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77},
                {77,77,78,256,257,258,164,164,164,164,164,164,76,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77},
                {77,77,78,74,74,74,74,74,74,74,74,74,106,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,46,77,77,77},
                {77,77,78,74,74,74,74,74,74,74,74,74,133,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,76,77,77,77},
                {77,77,78,74,74,74,74,74,74,74,74,74,163,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,76,77,77,77},
                {77,77,78,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,76,77,77,77},
                {77,77,78,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,76,77,77,77},
                {77,77,78,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,76,77,77,77},
                {77,77,17,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,282,74,74,74,74,74,76,77,77,77},
                {77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,312,74,74,74,74,74,76,77,77,77},
                {77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,312,74,74,74,74,74,76,77,77,77},
                {77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,312,74,74,74,74,74,76,77,77,77},
                {77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,312,74,74,74,74,74,76,77,77,77},
                {77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,312,74,74,74,74,74,76,77,77,77},
                {77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,312,74,74,74,74,74,76,77,77,77},
                {77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,312,74,74,74,74,74,76,77,77,77},
                {77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,312,74,433,434,435,74,76,77,77,77},
                {77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,312,74,463,464,465,74,76,77,77,77},
                {77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,312,74,74,74,74,74,76,77,77,77},
                {77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,17,281,281,281,281,281,16,77,77,77},
                {77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77},
                {77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77}};

            Inicio.Impassaveis = new Rectangle[] {
                new Rectangle(76,353,816,354),//1
                new Rectangle(860,708,215,12),//2
                new Rectangle(1057,171,12,554),//3
                new Rectangle(385,40,672,184),//4
                new Rectangle(96,36,288,92),//5
                new Rectangle(79,38,16,319)};//6

            Inicio.EscadasProximo = new Rectangle[] {
                new Rectangle(959, 609, 33, 58)};

            Inicio.EscadaEntrada = null;

            Inicio.NPCs = new PGLabirintos<TIdSaidas>.NPCDesc[] {
                new PGLabirintos<TIdSaidas>.NPCDesc(new Vector2(110,281),PGLabirintos<TIdSaidas>.NPCDesc.Direcoes.Direita)};

            Inicio.Dialogos = new PGLabirintos<TIdSaidas>.DialogosDesc[] {
                new DialogosDesc(new Rectangle(131, 236, 253, 29), 0)};

            Inicio.JogadorInicio = new Point(132, 138);
            #endregion

            #region Dados OneWay
            OneWay.Solo = new ushort[,] {
                {77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,47,341,341,341,46,77,77},
                {77,77,77,77,77,77,77,77,47,341,341,341,341,341,341,341,341,341,341,341,341,341,341,341,341,341,46,77,77,77,78,134,134,134,76,77,77},
                {77,47,341,341,341,46,77,77,78,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,76,77,77,77,78,164,164,164,76,77,77},
                {77,78,373,374,375,310,77,77,78,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,76,77,77,77,78,74,74,74,76,77,77},
                {77,78,403,404,405,310,77,77,78,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,76,77,77,77,78,74,74,74,76,77,77},
                {77,78,436,437,438,310,77,77,78,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,76,77,77,77,78,74,74,74,76,77,77},
                {77,78,74,74,74,310,77,77,78,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,76,77,77,77,78,74,74,74,76,77,77},
                {77,78,74,74,74,310,77,77,78,74,74,74,280,281,281,281,281,281,281,281,281,281,282,74,74,74,76,77,77,77,78,74,74,74,76,77,77},
                {77,78,74,74,74,310,77,77,78,74,74,74,76,77,77,77,77,77,77,77,77,77,78,74,74,74,106,107,341,107,108,74,74,74,76,77,77},
                {77,78,74,74,74,310,77,77,78,74,74,74,76,77,77,77,77,77,77,77,77,77,78,74,74,74,133,134,134,134,135,74,74,74,76,77,77},
                {77,78,74,74,74,310,77,77,78,74,74,74,106,107,107,107,107,107,107,107,107,46,78,74,74,74,163,164,164,164,165,74,74,74,76,77,77},
                {77,78,74,74,74,310,77,77,78,74,74,74,133,134,134,134,134,134,134,134,134,76,78,74,74,74,74,74,74,74,74,74,74,74,76,77,77},
                {77,78,74,74,74,310,77,77,78,74,74,74,163,164,164,164,164,164,164,164,164,76,78,74,74,74,74,74,74,74,74,74,74,74,76,77,77},
                {77,78,74,74,74,310,77,77,78,74,74,74,74,74,74,74,74,74,74,74,74,76,78,74,74,74,74,74,74,74,74,74,74,74,76,77,77},
                {77,78,74,74,74,310,77,77,78,74,74,74,74,74,74,74,74,433,434,435,74,76,17,281,281,281,281,281,281,281,282,74,74,74,76,77,77},
                {77,78,74,74,74,310,77,77,78,74,74,74,74,74,74,74,74,463,464,465,74,76,77,77,77,77,77,77,77,77,78,74,74,74,76,77,77},
                {77,78,74,74,74,310,77,77,17,281,281,281,281,281,281,281,281,281,281,281,281,16,77,77,77,77,77,77,77,77,78,74,74,74,76,77,77},
                {77,78,74,74,74,106,107,341,341,341,341,341,341,341,341,341,341,341,341,341,341,341,341,341,341,341,341,341,341,107,108,74,74,74,76,77,77},
                {77,78,74,74,74,133,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,135,74,74,74,76,77,77},
                {77,78,74,74,74,163,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,165,74,74,74,76,77,77},
                {77,78,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,76,77,77},
                {77,78,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,76,77,77},
                {77,78,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,76,77,77},
                {77,17,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,16,77,77},
                {77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77}};

            OneWay.Impassaveis = new Rectangle[] {
                new Rectangle(37,77,141,51),
                new Rectangle(48,66,16,704),
                new Rectangle(40,737,1086,11),
                new Rectangle(1089,3,10,762),
                new Rectangle(989,14,121,18),
                new Rectangle(833,3,159,317),
                new Rectangle(283,33,564,31),
                new Rectangle(163,36,120,572),
                new Rectangle(286,512,705,96),
                new Rectangle(737,449,254,63),
                new Rectangle(673,385,61,130),
                new Rectangle(385,224,349,160)};

            OneWay.EscadasProximo = new Rectangle[] {
                new Rectangle(577, 449, 34, 50)};

            OneWay.EscadaEntrada = new Rectangle(97,137,30,43);

            OneWay.Inimigos = new Vector2[] {
                new Vector2(98,403),
                new Vector2(338,658),
                new Vector2(628,661),
                new Vector2(1027,122),
                new Vector2(324,306),
                new Vector2(766,158)};

            OneWay.NPCs = null;

            OneWay.JogadorInicio = new Point(102, 187);
            #endregion

            #region Dados TwoWay
            TwoWay.Solo = new ushort[,] {
                {77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77},
                {77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77},
                {77,77,77,47,341,341,341,341,46,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,47,341,341,341,46,77},
                {77,77,77,78,134,134,134,134,76,77,77,47,341,341,341,341,341,341,341,341,341,341,341,341,341,341,341,341,341,341,107,108,373,374,375,76,77},
                {77,77,77,78,164,164,164,164,76,77,77,78,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,135,403,404,405,76,77},
                {77,77,77,78,74,433,434,435,76,77,77,78,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,165,436,437,438,76,77},
                {77,77,77,78,74,463,464,465,76,77,77,78,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,76,77},
                {77,47,107,108,74,74,74,74,76,77,77,78,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,76,77},
                {77,78,134,135,74,74,74,74,106,107,107,108,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,76,77},
                {77,78,164,165,74,74,74,74,133,134,134,135,74,74,74,74,74,74,74,74,74,74,74,280,281,281,281,281,281,281,281,281,281,281,281,16,77},
                {77,78,74,74,74,74,74,74,163,164,164,165,74,74,74,74,74,74,74,74,74,74,74,76,77,77,77,77,77,77,77,77,77,77,77,77,77},
                {77,78,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,76,77,77,77,77,77,77,77,77,77,77,77,77,77},
                {77,78,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,76,77,77,77,77,77,77,77,77,77,77,77,77,77},
                {77,17,281,281,281,281,281,281,281,281,281,282,74,74,74,74,74,74,74,74,74,74,74,76,77,77,77,77,77,77,77,77,77,77,77,77,77},
                {77,77,77,77,77,77,77,77,77,77,77,78,74,74,74,74,74,74,74,74,74,74,74,76,77,77,77,77,77,77,77,77,77,77,77,77,77},
                {77,77,77,77,77,77,77,77,77,77,77,78,74,74,74,74,74,74,74,74,74,74,74,76,77,77,77,77,77,77,77,77,77,77,77,77,77},
                {77,77,77,77,77,77,77,77,77,77,77,17,281,281,281,281,281,282,74,74,74,280,281,16,77,77,77,77,77,77,77,77,77,77,77,77,77},
                {77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,78,74,74,74,76,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77},
                {77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,78,74,74,74,106,107,341,341,341,341,341,341,341,341,341,341,46,77,77,77},
                {77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,78,74,74,74,133,134,134,134,134,134,134,134,134,134,134,134,76,77,77,77},
                {77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,78,74,74,74,163,164,164,164,164,164,164,164,164,164,164,164,76,77,77,77},
                {77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,78,74,74,74,74,74,74,74,74,74,74,74,74,433,434,435,76,77,77,77},
                {77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,78,74,74,74,74,74,74,74,74,74,74,74,74,463,464,465,76,77,77,77},
                {77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,17,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,16,77,77,77},
                {77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77}};

            TwoWay.Impassaveis = new Rectangle[] {
                new Rectangle(65,64, 63,224),
                new Rectangle(51,239,12,202),
                new Rectangle(41,417,343,12),
                new Rectangle(368,416,16,144),
                new Rectangle(361,512,215,11),
                new Rectangle(561,512,14,253),
                new Rectangle(555,736,546,11),
                new Rectangle(1057,642,10,121),
                new Rectangle(737,289,403,351),
                new Rectangle(671,512,67,128),
                new Rectangle(1120,54,15,352),
                new Rectangle(1001,75,149,27),
                new Rectangle(383,104,641,56),
                new Rectangle(256,55,128,265),
                new Rectangle(105,73,168,23)};

            TwoWay.EscadasProximo = new Rectangle[] {
                new Rectangle(192,160,34,57),
                new Rectangle(992,672,32,55)};

            TwoWay.EscadaEntrada = new Rectangle(1055, 126, 32, 50);

            TwoWay.Inimigos = new Vector2[] {
                new Vector2(449,232),
                new Vector2(637,386)};

            OneWay.NPCs = null;

            TwoWay.JogadorInicio = new Point(1060, 183);
            #endregion

            #region Dados SemFim
            SemFim.Solo = new ushort[,] {
                {77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77},
                {77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77},
                {77,77,77,77,77,77,47,341,341,341,341,341,341,341,341,341,46,77,77,77,77,77,77,77,77},
                {77,77,77,77,77,77,78,134,134,134,134,134,134,134,134,134,76,77,77,77,77,77,77,77,77},
                {77,77,77,77,77,77,78,134,134,134,373,374,375,134,134,134,76,77,77,77,77,77,77,77,77},
                {77,77,77,77,77,77,78,134,134,134,403,404,405,134,134,134,76,77,77,77,77,77,77,77,77},
                {77,77,77,77,77,77,78,164,164,164,436,437,438,164,164,164,76,77,77,77,77,77,77,77,77},
                {77,77,77,77,47,341,108,74,74,74,74,74,74,74,74,74,106,341,46,77,77,77,77,77,77},
                {77,77,77,77,312,134,135,79,79,79,79,79,79,79,79,79,133,134,76,77,77,77,77,77,77},
                {77,77,77,77,312,164,165,139,139,139,139,139,139,139,139,139,163,164,76,77,77,77,77,77,77},
                {77,77,77,77,312,74,74,74,74,74,74,74,74,74,74,74,74,74,76,77,77,77,77,77,77},
                {77,77,77,77,312,74,74,74,74,74,74,74,74,74,74,74,74,74,76,77,77,77,77,77,77},
                {77,77,77,77,312,74,74,74,74,74,157,158,159,160,161,162,74,74,76,77,77,77,77,77,77},
                {77,77,77,77,312,74,74,74,74,74,187,188,189,190,191,192,74,74,76,77,77,77,77,77,77},
                {77,77,77,77,312,74,74,74,74,74,217,218,219,220,221,222,74,74,76,77,77,77,77,77,77},
                {77,77,77,77,17,281,281,281,281,281,281,281,281,281,281,281,281,281,16,77,77,77,77,77,77},
                {77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77}};

            SemFim.Impassaveis = new Rectangle[] {
                new Rectangle(128,480,478,13),
                new Rectangle(576,238,11,275),
                new Rectangle(513,65,98,223),
                new Rectangle(415,112,101,80),
                new Rectangle(321,127,95,33),
                new Rectangle(188,147,132,45),
                new Rectangle(160,138,63,151),
                new Rectangle(143,223,17,288)};

            SemFim.EscadasProximo = null;

            SemFim.EscadaEntrada = new Rectangle(351, 162, 35, 45);

            SemFim.Inimigos = new Vector2[] {
                new Vector2(467,409),
                new Vector2(233,404),
                new Vector2(354,409)};

            OneWay.NPCs = null;

            SemFim.JogadorInicio = new Point(357, 218);
            #endregion

            #region Dados Fim
            Fim.Solo = new ushort[,] {
                {77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,47,341,341,341,341,341,341,341,341,341,341,46,77,77,77,77,77,77,77,77,77},
                {77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,312,134,134,134,134,376,377,378,134,134,134,310,77,77,77,77,77,77,77,77,77},
                {77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,312,134,134,134,134,406,407,408,134,134,134,310,77,77,77,77,77,77,77,77,77},
                {77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,312,164,164,164,164,436,437,438,164,164,164,310,77,77,77,77,77,77,77,77,77},
                {77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,312,79,79,79,79,79,79,79,79,79,79,310,77,77,77,77,77,77,77,77,77},
                {77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,312,109,109,109,109,109,109,109,109,109,109,310,77,77,77,77,77,77,77,77,77},
                {77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,312,139,139,139,139,139,139,139,139,139,139,310,77,77,77,77,77,77,77,77,77},
                {77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,312,74,74,74,74,74,74,74,74,74,74,310,77,77,77,77,77,77,77,77,77},
                {77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,312,79,79,79,79,79,79,79,79,79,79,310,77,77,77,77,77,77,77,77,77},
                {77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,312,109,109,109,109,109,109,109,109,109,109,310,77,77,77,77,77,77,77,77,77},
                {77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,312,139,139,139,139,139,139,139,139,139,139,310,77,77,77,77,77,77,77,77,77},
                {77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,312,74,74,74,74,74,74,74,74,74,74,310,77,77,77,77,77,77,77,77,77},
                {77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,312,74,74,74,74,74,74,74,74,74,74,310,77,77,77,77,77,77,77,77,77},
                {77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,312,79,79,79,79,79,79,79,79,79,79,310,77,77,77,77,77,77,77,77,77},
                {77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,312,109,109,109,109,109,109,109,109,109,109,310,77,77,77,77,77,77,77,77,77},
                {77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,312,139,139,139,139,139,139,139,139,139,139,310,77,77,77,77,77,77,77,77,77},
                {77,77,77,77,77,47,341,341,341,46,77,77,77,77,77,77,312,74,74,74,74,74,74,74,74,74,74,310,77,77,77,77,77,77,77,77,77},
                {77,77,77,77,77,312,373,374,375,340,341,341,341,341,341,341,108,74,74,74,74,74,74,74,74,74,74,310,77,77,77,77,77,77,77,77,77},
                {77,77,77,77,77,312,403,404,405,134,134,134,134,134,134,134,135,74,74,74,74,74,74,74,74,74,74,310,77,77,77,77,77,77,77,77,77},
                {77,77,77,77,77,312,436,437,438,164,164,164,164,164,164,164,165,74,74,74,74,74,74,74,74,74,74,310,77,77,77,77,77,77,77,77,77},
                {77,77,77,77,77,312,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,310,77,77,77,77,77,77,77,77,77},
                {77,77,77,77,77,312,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,310,77,77,77,77,77,77,77,77,77},
                {77,77,77,77,77,17,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,16,77,77,77,77,77,77,77,77,77},
                {77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77},
                {77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77}};
            
            Fim.Impassaveis = new Rectangle[] {
                new Rectangle(288,12,256,596),
                new Rectangle(168,528,141,16),
                new Rectangle(178,516,14,211),
                new Rectangle(162,704,745,15),
                new Rectangle(864,6,12,743),
                new Rectangle(767,36,118,60),
                new Rectangle(671,50,97,13),
                new Rectangle(520,64,152,32)};

            Fim.EscadasProximo = new Rectangle[] {
                new Rectangle(704,69,32,51)};

            Fim.EscadaEntrada = new Rectangle(224, 575, 32, 53);

            Fim.NPCs = new PGLabirintos<TIdSaidas>.NPCDesc[] {
                new NPCDesc(new Vector2(557,515),PGLabirintos<TIdSaidas>.NPCDesc.Direcoes.Baixo),
                new NPCDesc(new Vector2(625,515),PGLabirintos<TIdSaidas>.NPCDesc.Direcoes.Baixo),
                new NPCDesc(new Vector2(791,528),PGLabirintos<TIdSaidas>.NPCDesc.Direcoes.Esquerda),
                new NPCDesc(new Vector2(791,621),PGLabirintos<TIdSaidas>.NPCDesc.Direcoes.Esquerda)};

            Fim.Dialogos = new PGLabirintos<TIdSaidas>.DialogosDesc[] {
                new DialogosDesc(new Rectangle(553, 541, 223, 75), 1)};

            Fim.JogadorInicio = new Point(231, 638);

            #endregion

            this.listaProximos = listaProximos;
            this.saidaVolta = saidaVolta;
            this.alturaMaxima = altura;

            entradas = game.Services.GetService(typeof(IPGEntradasAcao)) as IPGEntradasAcao;
            labirintoGfx = PGIMGLabirinto.CriarTileset(game.Content);
            koboldGfx = PGIMGKobold.CriarTileset(game.Content);
            espadaGfx = PGIMGAtaqueEspada.CriarTileset(game.Content);
            ursoGfx = PGIMGUrso.CriarTileset(game.Content);
            placaGfx = game.Content.Load<Texture2D>(@"Images/Sprites/Placa");

            espadaSfx = PGSFXAtaqueEspada.CriarSoundEffect(game.Content);
            castursoSfx = PGSFXCasturso.CriarSoundEffect(game.Content);

            placaFont = game.Content.Load<SpriteFont>(@"Fonts/Storytelling");

            this.game = game;
        }

        public EntityManager ConstruirLabirintoInicio(uint altura, EventHandler<MudaMapaEventArgs<TIdSaidas>> escadas_handler, EventHandler jogador_conversa)
        {
            return ConstruirLabirinto(altura, Inicio, escadas_handler, jogador_conversa);
        }

        public EntityManager ConstruirLabirintoOneWay(uint altura, EventHandler<MudaMapaEventArgs<TIdSaidas>> escadas_handler, EventHandler jogador_conversa)
        {
            return ConstruirLabirinto(altura, OneWay, escadas_handler, jogador_conversa);
        }

        public EntityManager ConstruirLabirintoTwoWay(uint altura, EventHandler<MudaMapaEventArgs<TIdSaidas>> escadas_handler, EventHandler jogador_conversa)
        {
            return ConstruirLabirinto(altura, TwoWay, escadas_handler, jogador_conversa);
        }

        public EntityManager ConstruirLabirintoSemFim(uint altura, EventHandler<MudaMapaEventArgs<TIdSaidas>> escadas_handler, EventHandler jogador_conversa)
        {
            return ConstruirLabirinto(altura, SemFim, escadas_handler, jogador_conversa);
        }

        public EntityManager ConstruirLabirintoFim(uint altura, EventHandler<MudaMapaEventArgs<TIdSaidas>> escadas_handler, EventHandler jogador_conversa)
        {
            return ConstruirLabirinto(altura, Fim, escadas_handler, jogador_conversa);
        }

        EntityManager ConstruirLabirinto(uint altura, LabirintoDesc labirinto, EventHandler<MudaMapaEventArgs<TIdSaidas>> escadas_handler, EventHandler jogador_conversa)
        {
            const float planoFundo = 1f;
            const float planoItens = planoFundo / 2;
            const float planoAcao = planoItens / 2;

            EntityManager novoLabirinto = new EntityManager(game);

            Tilemap solo = new Tilemap(labirinto.Solo, labirintoGfx);
            solo.LayerDepth = planoFundo;
            solo.CollisionType = TiposColisoes.Nenhum;
            novoLabirinto.AddEntity(solo);
            novoLabirinto.WorldBounds = solo.Bounds;

            PGAtaqueEspada ataque = PGAtaqueEspada.CriarAtaqueEspada(espadaGfx, espadaSfx);
            novoLabirinto.AddEntity(ataque);

            PGSpritePlaca placa = new PGSpritePlaca(placaFont, placaGfx);
            placa.LayerDepth = planoItens;
            placa.Numero = (int)(alturaMaxima - altura);
            novoLabirinto.AddEntity(placa);

            AtributosJogador atributosJogador = game.Services.GetService(typeof(AtributosJogador)) as AtributosJogador;

            PGSpriteJogador jogador = new PGSpriteJogador(atributosJogador,ataque, entradas, koboldGfx);
            jogador.Position = new Vector2(labirinto.JogadorInicio.X, labirinto.JogadorInicio.Y);
            jogador.LayerDepth = planoAcao;
            jogador.ItemMarcador = placa;
            novoLabirinto.AddEntity(jogador);
            novoLabirinto.FrameFocus = jogador;

            foreach (Rectangle area in labirinto.Impassaveis)
            {
                PGAreaColisao areaImpassavel = new PGAreaColisao(area);
                areaImpassavel.CollisionType = TiposColisoes.Solido;

                novoLabirinto.AddEntity(areaImpassavel);
            }

            if (labirinto.EscadasProximo != null)
            {
                int i = 0;
                foreach (Rectangle escada in labirinto.EscadasProximo)
                {
                    PGGatilhoMudaMapa<TIdSaidas> areaEscada = new PGGatilhoMudaMapa<TIdSaidas>(escada, listaProximos[i++]);
                    areaEscada.CollisionType = TiposColisoes.Solido;
                    areaEscada.Triggered += new EventHandler<MudaMapaEventArgs<TIdSaidas>>(escadas_handler);

                    novoLabirinto.AddEntity(areaEscada);
                }
            }

            if (labirinto.EscadaEntrada != null)
            {
                PGGatilhoMudaMapa<TIdSaidas> areaEscadaEntrada = new PGGatilhoMudaMapa<TIdSaidas>((Rectangle)labirinto.EscadaEntrada, saidaVolta);
                areaEscadaEntrada.CollisionType = TiposColisoes.Solido;
                areaEscadaEntrada.Triggered += new EventHandler<MudaMapaEventArgs<TIdSaidas>>(escadas_handler);
                novoLabirinto.AddEntity(areaEscadaEntrada);
            }

            if (labirinto.Inimigos != null)
            {
                foreach (Vector2 posInimigo in labirinto.Inimigos)
                {
                    PGSpriteInimigo inimigo = new PGSpriteUrso(castursoSfx, ursoGfx);
                    inimigo.Position = posInimigo;
                    novoLabirinto.AddEntity(inimigo);
                }
            }

            if (labirinto.NPCs != null)
            {
                foreach (NPCDesc npcdesc in labirinto.NPCs)
                {
                    PGNPC npc = new PGNPCKobold(koboldGfx);
                    npc.Position = npcdesc.Posicao;
                    npc.LayerDepth = planoAcao;
                    npc.ColorEffects = Color.LightSalmon;

                    switch (npcdesc.Direcao)
                    {
                        case PGLabirintos<TIdSaidas>.NPCDesc.Direcoes.Baixo:
                            npc.ViradoBaixo();
                            break;

                        case PGLabirintos<TIdSaidas>.NPCDesc.Direcoes.Cima:
                            npc.ViradoCima();
                            break;

                        case PGLabirintos<TIdSaidas>.NPCDesc.Direcoes.Esquerda:
                            npc.ViradoEsquerda();
                            break;

                        case PGLabirintos<TIdSaidas>.NPCDesc.Direcoes.Direita:
                            npc.ViradoDireita();
                            break;
                    }

                    novoLabirinto.AddEntity(npc);
                }
            }

            if (labirinto.Dialogos != null)
            {
                foreach (DialogosDesc dd in labirinto.Dialogos)
                {
                    PGGatilhoJogador gj = new PGGatilhoJogador(dd.Regiao);
                    gj.Id = dd.Id;
                    gj.CollisionType = TiposColisoes.Nenhum;
                    gj.Triggered += new EventHandler<EventArgs>(jogador_conversa);

                    novoLabirinto.AddEntity(gj);
                }
            }

            return novoLabirinto;
        }
    }
}
